//
//  AppDelegate.swift
//  AppDelegate是全局只有一个实例
//  他的功能就是代理了系统的一些事件
//  例如：APP后台了，前台了等事件
//  后面用到的时候在讲解
//
//  Created by smile on 2019/4/5.
//  Copyright © 2019 ixuea. All rights reserved.
//

import UIKit

//音乐播放
import AVFoundation

//发布订阅框架
import SwiftEventBus

//通知框架
//包括本地通知
//远程通知（未实现）
import UserNotifications

//主题框架
import SwiftTheme

//日志框架
import CocoaLumberjack

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    
    var window: UIWindow?
    
    /// 播放列表管理器
    var playListManager:PlayListManager!
    
    /// 音乐播放器管理器
    var musicPlayerManager:MusicPlayerManager?
    
    /// 当前正在和谁聊天
    /// 也就是在聊天界面
    /// 这里是用户Id
    var currentChatUserId:String?
    
    //默认为竖屏
    var orientationMask = UIInterfaceOrientationMask.portrait
    
    /// 是否恢复音乐播放
    var isResumePlay = false
    
    /// 定义一个静态的shared计算属性
    /// 他返回AppDelegate对象实例
    open class var shared: AppDelegate {
        get {
            return UIApplication.shared.delegate as! AppDelegate
        }
    }
    
    /// 跳转到引导界面
    // 为什么跳转到引导界面要写到AppDelegate中呢？
    // 因为这里的跳转界面，我们不希望用户还能返回
    // 所以直接将当前的window里面的根控制器设置为了引导界面
    // 实现的效果是用户在引导界面无法再返回到启动界面
    // 这也是符合大部分APP的规范
    func toGuide() {
        //获取到Main.storyboard
//        let mainStory=UIStoryboard(name: "Main", bundle: nil)
//
//        //实例化Guide场景，因为场景有控制器
//        //所以也可以说实例化控制器
          //但实例化过程是系统完成的
//        //不是我们手动创建的
//        let controller=mainStory.instantiateViewController(withIdentifier: "Guide")
//
//        //这里替换到原来的根控制器
//        //目的是，我们不希望用户还能返回到给界面
//        self.window!.rootViewController = controller;
        
        setRootViewController(name: "Guide")
    }
    
    /// 跳转到登陆/注册页面
    func toLoginOrRegister() {
//        //获取到Main.storyboard
//        let mainStory=UIStoryboard(name: "Main", bundle: nil)
//
//        //实例化Guide场景，因为场景有控制器
//        //所以也可以说实例化控制器，但实例化过程是系统完成的
//        //不是我们手动创建的
//        let controller=mainStory.instantiateViewController(withIdentifier: "LoginOrRegister")
//
//        //这里替换到原来的根控制器
//        //目的是，我们不希望用户还能返回到给界面
//        self.window!.rootViewController = controller
        
//        原来是跳转到登陆注册界面
//        setRootViewController(name: "LoginOrRegister")
        
//        嵌入导航器后，要跳转到对应界面的导航器
        setRootViewController(name: "LoginOrRegisterNavigation")
    }
    
    /// 退出方法
    func logout()  {
        /// 退出
        //如果需要调用接口
        //就在这里调用就行了
        
        //清除用户信息
        PreferenceUtil.logout()
        
        //清除第三方登陆Token
        //清除QQ
        ShareSDK.cancelAuthorize(SSDKPlatformType.typeQQ, result: nil)
        
        //清除微博
        ShareSDK.cancelAuthorize(SSDKPlatformType.typeSinaWeibo, result: nil)
        
        //进入登陆注册界面
        toLoginOrRegister()
        
        //退出极光聊天
        JMSGUser.logout(nil)
    }
    
    //在iOS中，有两种通知，一种是远程通知
    //远程通知：简单理解为苹果服务器发消息到应用
    //本地通知：应用中发送一个通知
    //因为我们没有iOS付费开发者账号
    //所以只能实现本地通知
    //同时聊天服务依赖远程通知
    //所以当现在的应用后台以后
    //过一段时间无法收到聊天通知
    //因为后台以后过一会儿
    //应用就被暂停了
    //就无法通过应用内容的了解接收消息
    //所以真实项目中一定要有开发者账号才行
    func initNotification() {
        // 使用 UNUserNotificationCenter 来管理通知
        let center=UNUserNotificationCenter.current()
        
        //监听回调事件
        center.delegate = self
        
        //iOS 10使用以下方法注册
        //才能得到授权，注册通知以后
        //会自动注册 deviceToken
        //如果获取不到 deviceToken Xcode8下要注意开启 Capability->Push Notification
        //开启Push Notification
        //需要付费的开发者Id
        //因为我们没有付费开发者账号
        //所以一下注册肯定是会失败的
        center.requestAuthorization(options: [UNAuthorizationOptions.alert,UNAuthorizationOptions.sound, .badge]) { (granted, error) in
            if granted {
                print("AppDelegate initNotification notification granted")
            }else{
                print("AppDelegate initNotification notification not granted")
            }
        }
        
    }
    
    /// 跳转到首页
    func toHome() {
        //通知相关
        initNotification()
        
        //音乐播放
        initMedia()
        
        //监听消息未读数改变了
        SwiftEventBus.onMainThread(self, name: ON_MESSAGE_COUNT_CHANGED) { (sender) in
            UIApplication.shared.applicationIconBadgeNumber=MessageUtil.getUnreadMessageCount()
        }
        
//        //获取到Main.storyboard
//        let mainStory=UIStoryboard(name: "Main", bundle: nil)
//
//        //实例化Guide场景，因为场景有控制器
//        //所以也可以说实例化控制器，但实例化过程是系统完成的
//        //不是我们手动创建的
//        let controller=mainStory.instantiateViewController(withIdentifier: "Home")
//
//        //这里替换到原来的根控制器
//        //目的是，我们不希望用户还能返回到给界面
//        self.window!.rootViewController = controller;
        
        setRootViewController(name: "Home")
        
        
    }
    
    /// 进入首页
    ///
    /// - Parameter uri: <#uri description#>
    func toHome(_ uri:String?){
        toHome()
        
        if let uri = uri{
            //如果有广告地址，就发送一个通知
            //为什么要通过通知发送呢
            //其实是因为我们在AppDelegate中要拿到发现界面控制器比较麻烦
            DispatchQueue.main.async {
                NotificationCenter.default.post(name: NSNotification.Name(rawValue: AD_CLICK), object: nil, userInfo: ["uri":uri])
            }
        }
    }
    
    /// 显示启动界面广告
    func toAd() {
        //可以看到使用自定义的方法
        //要启动一个界面就非常简单了
        setRootViewController(name: "Ad")
    }
    
    /// 设置根控制器
    ///
    /// - Parameter name: 要显示的场景名称
    func setRootViewController(name:String) {
        //获取到Main.storyboard
        let mainStory=UIStoryboard(name: "Main", bundle: nil)
        
        //实例化Guide场景，因为场景有控制器
        //所以也可以说实例化控制器，但实例化过程是系统完成的
        //不是我们手动创建的
        let controller=mainStory.instantiateViewController(withIdentifier: name)
        
        //这里替换到原来的根控制器
        //目的是，我们不希望用户还能返回到给界面
        self.window!.rootViewController = controller

    }
    
    /// 初始化ShareSDK
    func initShareSDK() {
        ShareSDK.registPlatforms {  register in
            
            //设置QQ配置
            register?.setupQQ(withAppId: QQ_APP_KEY, appkey: QQ_APP_SECRET)
            
            //设置微信配置
//            register?.setupWeChat(withAppId: "wx617c77c82218ea2c", appSecret: "c7253e5289986cf4c4c74d1ccc185fb1")
//
//            //设置微博配置
            register?.setupSinaWeibo(withAppkey: WEIBO_APP_KEY, appSecret: WEIBO_APP_SECRET, redirectUrl: WEIBO_REDIRECT_URI)
        }
    }
    
    /// 初始化TabBar
    func initTabBar() {
        //TabBar
        //选中颜色设置
//        UITabBar.appearance().tintColor=UIColor(hex: COLOR_PRIMARY)
//
//        //TabBar选中高亮颜色
//        UITabBar.appearance().theme_barTintColor=[COLOR_STRING_WHITE,COLOR_STRING_DARK_BLACK]
    }
    
    /// 初始化媒体
    func initMedia() {
        //播放列表管理器
        playListManager=PlayListManager.shared
        
        //播放管理器
        musicPlayerManager=MusicPlayerManager.shared()
        
        
        //设置类别；简单来讲类别就是一系列动作的预设
        //AVAudioSessionCategoryPlayback:为后台播放
        //表示独占
        //静音按钮对他无效
        let session=AVAudioSession.sharedInstance()

        try! session.setCategory(AVAudioSession.Category.playback, mode: AVAudioSession.Mode.default, options:[])

        //激活音频会话
        try! session.setActive(true, options: [])

        //告诉系统，我们要接受远程控制事件
        UIApplication.shared.beginReceivingRemoteControlEvents()

        //设置响应者
        becomeFirstResponder()

        //监听耳机插入和拔掉通知
        NotificationCenter.default.addObserver(self, selector: #selector(onAudioRouteChanged(notification:)), name: AVAudioSession.routeChangeNotification, object: nil)
        
        //监听其他音频中断
        //包括其他软件播放音乐
        //当然播放视频也算
        //拨打电话
        //来电
        NotificationCenter.default.addObserver(self, selector: #selector(onInterruptionChanged(notification:)), name: AVAudioSession.interruptionNotification, object: nil)
    }
    
    /// 音频输入中断了
    /// 包括其他软件播放音乐
    /// 电话
    ///
    /// - Parameter notification: <#notification description#>
    @objc func onInterruptionChanged(notification:Notification) {
        print("AppDelegate onInterruptionChanged")
 
        //将这个三个变量都拆包
        //只要有一个拆包不成功就返回了
        guard let userInfo = notification.userInfo,
            let interruptionTypeRawValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt,
            let interruptionType = AVAudioSession.InterruptionType(rawValue: interruptionTypeRawValue) else {
                return
        }
        
        switch interruptionType {
        case .began:
            //中断事件开始
            //例如：开始拨打电话，或者接听电话
            print("AppDelegate onInterruptionChanged begin")
            if musicPlayerManager!.isPlaying() {
                //音乐原来在播放
                playListManager.pause()
                
                //自动恢复
                isResumePlay=true
            }
        case .ended:
            //中断事件结束
            //例如：挂断电话
            print("AppDelegate onInterruptionChanged ended")
            
            if isResumePlay {
                //自动恢复播放
                playListManager.resume()
                
                //清除自动恢复标志
                isResumePlay=false
            }
        }
        
        
    }
    
    /// 音频输出改变通知
    ///
    /// - Parameter notification: <#notification description#>
    @objc func onAudioRouteChanged(notification:Notification) {
        let userInfo=notification.userInfo
        
        print("AppDelegate onAudioRouteChanged:\(userInfo)")
        
        let type = userInfo![AVAudioSessionRouteChangeReasonKey] as! Int

        switch type {
        case kAudioSessionRouteChangeReason_NewDeviceAvailable:
            //耳机插入
            print("AppDelegate onAudioRouteChanged new device available")
        case kAudioSessionRouteChangeReason_OldDeviceUnavailable:
            //耳机拔掉
            print("AppDelegate onAudioRouteChanged new device unavailable")

            if PreferenceUtil.isRemoveHeadsetStop() {
                //如果需要停止
                if musicPlayerManager!.isPlaying() {
                    //如果正在播放
                    //就停止
                    playListManager.pause()
                }
           
            }

        default:
            break
        }
    }
    
    /// 初始化高德地图
    func initAMap() {
        AMapServices.shared().apiKey = AMAP_KEY
    }
    
    
    /// 初始化主题
    func initTheme() {
        setNight(PreferenceUtil.isNight())
    }
    
    /// 更改主题方法
    ///
    /// - Parameter isNight: <#isNight description#>
    func setNight(_ isNight:Bool) {
        //0:表示主题数组中第1个元素,白天
        //1:表示椎体数组中的2个元素,夜间
        ThemeManager.setTheme(index: isNight ? 1:0)
    }
    
    func initLog() {
//        //日志打印到控制台
//        DDLog.add(DDOSLogger.sharedInstance) // Uses os_log
//
//        //打印到文件
//        let fileLogger: DDFileLogger = DDFileLogger()
//
//        //每个文件保存24小时日志
//        //也就是每天的日志保存到一个文件
//        fileLogger.rollingFrequency = 60 * 60 * 24
//
//        //保存最近7天日志
//        fileLogger.logFileManager.maximumNumberOfLogFiles = 7
//
//        //将配置点击日志框架
//        DDLog.add(fileLogger)
        
        //定制日志规则
        if DEBUG {
            //调试状态下
            //日志打印到控制台
            let ddosLogger=DDOSLogger.sharedInstance!
            
            //设置日志格式
            setLogFormat(ddosLogger)
            
            DDLog.add(ddosLogger)
        }
        
        //所有环境，日志打印的文件
        let fileLogger: DDFileLogger = DDFileLogger()
        
        //每个文件保存24小时日志
        //也就是每天的日志保存到一个文件
        fileLogger.rollingFrequency = 60 * 60 * 24
        
        //总共保存最近30天的日志
        fileLogger.logFileManager.maximumNumberOfLogFiles = 30
        
        //设置日志格式
        setLogFormat(fileLogger)
        
        //文件中只保存警告及以上等级日志
        DDLog.add(fileLogger, with: .warning)
        
        //使用日志API打印日志
        DDLogVerbose("Ixuea Verbose")
        DDLogDebug("Ixuea Debug")
        DDLogInfo("Ixuea Info")
        DDLogWarn("Ixuea Warn")
        DDLogError("Ixuea Error")
        
        //使用日志TAG
        DDLogVerbose("Ixuea Verbose",tag: "aaaaaaa")
        
        //获取日志文件夹路径
        let logsDirectory=fileLogger.logFileManager.logsDirectory
        print("AppDelegate log path:\(logsDirectory)")
        
        //获取排序后的日志名称
        let logFilenames = fileLogger.logFileManager.sortedLogFileNames
        print("AppDelegate log files:\(logFilenames.count)")

    }
    
    /// 设置日志格式
    ///
    /// - Parameter logger: <#logger description#>
    func setLogFormat(_ logger:DDAbstractLogger) {
        //设置日志格式
        //可以根据版本设置不同的格式
        //例如：debug模式下
        //日志格式信息更丰富，可以有方法名
        //行号；这样更容易查找错误
        
        //release：格式更紧凑，只留有用的信息
        logger.logFormatter=LogFormat()
    }
    
    /// 腾讯Bugly
    func initBugly() {
        let config=BuglyConfig()
        config.debugMode=true
        
        Bugly.start(withAppId: BUGLY_APP_KEY)
        
//        Bugly.start(withAppId: BUGLY_APP_KEY, config: config)
    }
    
    /// 初始化极光相关服务
    ///
    /// - Parameter launchOptions: <#launchOptions description#>
    func initJIGUANG(launchOptions: [UIApplication.LaunchOptionsKey: Any]?) {
        //添加极光聊天回调
        JMessage.add(self, with: nil)
        
        //初始化极光聊天
        JMessage.setupJMessage(launchOptions, appKey: JIGUANG_APP_KEY, channel: JIGUANG_CHANNEL, apsForProduction: true, category: nil, messageRoaming: false)
        
        //极光分析
        let config = JANALYTICSLaunchConfig()
        
        //AppKey
        config.appKey = JIGUANG_APP_KEY
        
        //渠道
        config.channel = JIGUANG_CHANNEL
        
        //初始化
        JANALYTICSService.setup(with: config)
        
        //开启崩溃日志统计
        JANALYTICSService.crashLogON()
        
        //设置调试模式
        JANALYTICSService.setDebug(DEBUG)
    }
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        //日志
        initLog()
        
        //腾讯Bugly
        initBugly();
        
        //主题
        initTheme()
        
        //初始化ShareSDK
        initShareSDK()
        
        //TabBar
        initTabBar()
        
        //极光
        initJIGUANG(launchOptions: launchOptions)
        
        //初始化高德地图
        initAMap()
        
        return true
    }



    func applicationWillResignActive(_ application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    }

    /// 当应用被终止时调用
    ///
    /// - Parameter application: <#application description#>
    func applicationWillTerminate(_ application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
        print("AppDelegate applicationWillTerminate")
        
        //应用被杀掉后
        //保存当前音乐信息
        //其他包括了进度
        //时长
        //用于继续播放
        musicPlayerManager?.saveCurrentSong()
    }
    
    /// 返回屏幕支持旋转的方向
    ///
    /// - Parameters:
    ///   - application: <#application description#>
    ///   - window: <#window description#>
    /// - Returns: <#return value description#>
    func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        return orientationMask
    }


    // MARK: - 远程控制音乐
    //第一响应者
    override var canBecomeFirstResponder: Bool{
        return true
    }
   
    // iOS有线耳机功能
    // 音量+
    // 控制按钮：单击：暂停或播放；双击：下一曲；三击；长按：Siri
    // 音量-
    
    /// 接收远程播放控制消息
    /// 包括系统控制中心对音乐的操作
    /// 有线耳机控制
    /// 蓝牙耳机控制
    ///
    /// - Parameter event: <#event description#>
    override func remoteControlReceived(with event: UIEvent?) {
        print("remoteControlReceived:\(event?.type),\(event?.subtype)")
        
        if event?.type == UIEvent.EventType.remoteControl {
            if playListManager.currentSong == nil{
                //当前没有可播放的音乐就返回
                return;
            }
            
            switch event!.subtype {
            case .remoteControlPlay:
                //点击了播放
                playListManager.resume()
                print("AppDelegate play")
            case .remoteControlPause:
                //点击了暂停
                playListManager.pause()
                print("AppDelegate pause")
            case .remoteControlNextTrack:
                //下一曲
                //双击iPhone耳机上的控制按钮会调用这里
                
                let song = playListManager.next()
                playListManager.play(song!)
                print("AppDelegate Next")
            case .remoteControlPreviousTrack:
                //上一曲
                //三击iPhone耳机上的控制按钮会调用这里

                let song = playListManager.previous()
                playListManager.play(song!)
                print("AppDelegate Previous")
            case .remoteControlTogglePlayPause:
                print("AppDelegate remoteControlReceived remoteControlTogglePlayPause")
                //单击耳机上的控制按钮会调用这里
                
                //我们这里实现暂停或播放功能
                playOrPause()
                
            default:
                break
            }
        }
        
    }
    
    /// 播放或者暂停音乐
    func playOrPause() {
        if musicPlayerManager!.isPlaying() {
            playListManager.pause()
            
        } else {
            playListManager.resume()
            
        }
    }

    /// 当其他应用唤醒当前应用时调用
    ///
    /// - Parameters:
    ///   - app: <#app description#>
    ///   - url: <#url description#>
    ///   - options: <#options description#>
    /// - Returns: <#return value description#>
    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
        print("AppDelegate Previous")
        
        if url.host == "safepay" {
            //如果手机中安装了支付宝客户端
            //跳转到支付宝客户端的支付结果从这里获取
            AlipaySDK.defaultService()!.processOrder(withPaymentResult: url) { (data) in
                print("AppDelegate open url alipay url:\(url),data:\(data)")
                
                //将支付支付状态发送出去
                SwiftEventBus.post(ON_ALIPAY_CALLBACK, sender: data as! [String:Any])
            }
        }
        
        return true
    }
}

// MARK: - 极光聊天代理
extension AppDelegate:JMessageDelegate{
    
    /// 聊天框架中数据库开始升级
    func onDBMigrateStart() {
        print("AppDelegate onDBmigrateStart")
        
    }
    
    
    /// 极光聊天在线消息回调
    ///
    /// - Parameters:
    ///   - message: <#message description#>
    ///   - error: <#error description#>
    func onReceive(_ message: JMSGMessage!, error: Error!) {
        print("AppDelegate onReceive:\(message.contentType),\(MessageUtil.getUnreadMessageCount()),\(message.content)")
        
        //将消息，显示到通知栏
        let target=message.fromUser
        if target.username==currentChatUserId {
            //正在和这个人聊天
            print("AppDelegate onReceive chat:\(target.username)")
        } else {
            print("AppDelegate onReceive show notification:\(target.username)")
            NotificationUtil.showMessage(message)
        }
        
    }
}

// MARK: - 系统通知代理
extension AppDelegate:UNUserNotificationCenterDelegate{
    
    /// 用户点击通知打开应用前
    ///
    /// - Parameters:
    ///   - center: <#center description#>
    ///   - response: <#response description#>
    ///   - completionHandler: <#completionHandler description#>
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        //处理通知
        print("AppDelegate didReceive")
        
        //推送中的信息
        let userInfo = response.notification.request.content.userInfo
        
        let action=userInfo[ACTION_KEY] as! String
        if ACTION_MESSAGE==action {
            
            //跳转到聊天界面
            let userId=userInfo[EXTRA_ID] as! String
            
            //获取到tabBarController
            let tabBarController = self.window!.rootViewController as! UITabBarController

            //获取到navigationController
            //先获取所有tabbar里面的控制器
            //然后获取当前选中的控制器
            let navigationController = tabBarController.viewControllers![tabBarController.selectedIndex] as! UINavigationController

            //跳转
            ChatController.start(navigationController, userId)
            
        }
        
        //处理完成后调用completionHandler完成后续操作
        completionHandler()
    }
    
    /// 在展示通知前进行处理
    /// 即有机会在展示通知前再修改通知内容
    ///
    /// - Parameters:
    ///   - center: <#center description#>
    ///   - notification: <#notification description#>
    ///   - completionHandler: <#completionHandler description#>
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        
        //处理通知
        print("AppDelegate willPresent")
        
        //处理完成后调用completionHandler完成后续操作
        completionHandler(UNNotificationPresentationOptions.alert)
        
    }
    
    
}
